//======================================================================================
/** \file mototest.cpp
 *    This file contains a program to test the ME 405 board's motor driver. It makes a
 *    motor move at speeds determined by the value read from a potentiometer connected 
 *    to the AVR's analog inputs. 
 *
 *  Revisions
 *    \li 01-05-2008 JRR Original file
 *    \li 02-03-2008 JRR Various cleanup, tested on new ME 405 boards
 *    \li 01-15-2008 JRR Changed to new file/directory layout with ./lib and *.cpp
 *    \li 01-19-2011 JRR Updated calls to newer version of stl_task constructor
 *
 *  License:
 *    This file released under the Lesser GNU Public License, version 2. This program
 *    is intended for educational use only, but it is not limited thereto. 
 */
//======================================================================================

											// System headers included with < >
#include <stdlib.h>							// Standard C library
#include <avr/io.h>							// Input-output ports, special registers
#include <avr/interrupt.h>					// Interrupt handling functions

											// User written headers included with " "
#include "rs232int.h"						// Serial port header
#include "global_debug.h"					// Header for serial debugging port
#include "stl_timer.h"						// Microsecond-resolution timer
#include "avr_adc.h"						// A/D converter header
#include "motor405.h"						// Driver for motors connected to board
#include "stl_task.h"						// Base class for all task classes
#include "task_motor.h"						// The task that runs the motor around
#include "task_user.h"						// The task that listens to the user

#define DIA_LED	0x01
#define DIA_DDR DDRB
#define DIA_PORT PORTB
//--------------------------------------------------------------------------------------
/** The main function is the "entry point" of every C program, the one which runs first
 *  (after standard setup code has finished). For mechatronics programs, main() runs an
 *  infinite loop and never exits. 
 */

int main ()
{
	volatile unsigned int dummy = 0;		// Delay loop kind of counter
	char time_string[16];					// Character buffer holds printable time
	char input_char;						// A character typed by the user
	unsigned char motor_duty = 0;			// Duty cycle to send to motor
	bool going_clockwise = true;			// Which way is the motor going? 

	// Create a serial port object. Messages will be printed to this port, which
	// should be hooked up to a dumb terminal program like minicom on a PC
	rs232 the_serial_port (9600, 0);
	set_glob_debug_port (&the_serial_port);

	// Print a greeting message. This is almost always a good thing because it lets 
	// the user know that the program is actually running
	the_serial_port << clrscr << "ME405 Board Motor Test & Task Demo" << endl
					<< "  CPU Freq: " << F_CPU << " Hz" << endl;

	// Create a really basic no-frills analog to digital converter interface object
	avr_adc my_adc (&the_serial_port);

	// Create a microsecond-resolution timer
	task_timer the_timer;

	// Create an ME405 board motor controller object for the first motor
	motor405 my_motor_1 (1);

	// Create another ME405 motor controller for the second motor
	motor405 my_motor_2 (2);

	// Create a time stamp which holds the interval between runs of the motor task
	// The time stamp is initialized with a number of seconds, then microseconds
	time_stamp interval_time (0, 10000);
	the_serial_port << "  Motor Task Interval: " << interval_time << " sec or " 
					<< interval_time.get_raw_time () << " counts" << endl;

	// Create a task which uses the A/D and motor controller to move a motor around
	task_motor mo_task (the_timer, interval_time, &my_motor_1, &my_motor_2, &my_adc);

	// Set the interval a bit slower for the user interface task
	interval_time.set_time (0, 50000);
	the_serial_port << "  User Interface Task Interval: " << interval_time << " sec or "
					<< interval_time.get_raw_time () << " counts" << endl;

	// Create a task to read commands from the keyboard
	task_user user_task (the_timer, interval_time, &mo_task, &my_adc, &the_serial_port);

	// Turn on interrupt processing so the timer can work
	sei ();

	DIA_DDR |= DIA_LED;
	DIA_PORT |= DIA_LED;
	
	// Run the main scheduling loop, in which the tasks are continuously scheduled.
	// This program currently uses very simple "round robin" scheduling in which the
	// tasks are simply called in order. More sophisticated scheduling strategies
	// will be used in other more sophisticated programs
	while (true)
	{
		mo_task.schedule ();
		user_task.schedule ();
	}

	return (0);
}

